// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <memory>
#include <optional>
#include <regex>
#include <string>

#include "coin2/exchange/base/symbology/spot_product.h"
#include "coin2/exchange/base/symbology/util.h"
#include "coin2/exchange/huobi/symbology/currency.h"

namespace coin2::exchange::huobi::symbology {

class HuobiProduct : public base::symbology::SpotProduct<HuobiCurrency, HuobiProduct>,
                     public base::symbology::ProductFromStrMixin<HuobiProduct> {
 public:
  using BaseProduct = SpotProduct<HuobiCurrency, HuobiProduct>;

  using ExchangeType = base::market::ExchangeType;
  using MarketType = base::market::MarketType;
  using CurrencyT = HuobiCurrency;
  static const ExchangeType kExchange = ExchangeType::Huobi;
  static const MarketType kMarketType = MarketType::Spot;

 public:
  HuobiProduct(const HuobiCurrency& base, const HuobiCurrency& quote)
      : SpotProduct(
            base,
            quote,
            ToHuobiNativeProduct(base, quote),
            ToHuobiNativeProduct(base, quote),
            base::market::ExchangeType::Huobi) {}

 public:
  static std::unique_ptr<HuobiProduct> FromNativeStrImpl(
      const std::string& native_product,
      int64_t resolve_timestamp) {
    std::unique_ptr<HuobiCurrency> base_ptr;
    std::unique_ptr<HuobiCurrency> quote_ptr;
    bool success =
        ParseHuobiNativeProduct(native_product, resolve_timestamp, &base_ptr, &quote_ptr);
    if (success) {
      return std::make_unique<HuobiProduct>(*base_ptr, *quote_ptr);
    } else {
      return {};
    }
  }

 private:
  static bool ParseHuobiNativeProduct(
      const std::string& product_str,
      int64_t resolve_timestamp,
      std::unique_ptr<HuobiCurrency>* base_ptr,
      std::unique_ptr<HuobiCurrency>* quote_ptr) {
    static const std::regex reg(
        "^([a-z0-9]{1,12})(btc|eth|ht|husd|usdc|usdt|ust|try|eur|gbp|usdd|brl|euroc|rub|tusd|uah|"
        "trx|usdc|usdd)$");
    std::smatch match;
    bool res = std::regex_match(product_str, match, reg);
    if (!res) return false;

    std::string base = match[1];
    std::string quote = match[2];
    *base_ptr = HuobiCurrency::FromNativeStrNoThrow(base, resolve_timestamp);
    *quote_ptr = HuobiCurrency::FromNativeStrNoThrow(quote, resolve_timestamp);
    return true;
  }

  static std::string ToHuobiNativeProduct(const HuobiCurrency& base, const HuobiCurrency& quote) {
    using base::market::MarketType;
    std::stringstream ss;
    ss << base.native_currency() << quote.native_currency();
    return ss.str();
  }
};

}  // namespace coin2::exchange::huobi::symbology
